package com.company.编译原理.DFA;

/**
 * @ClassName DFA2
 * @Description TODO
 * @Author 11
 * @Date 2021/3/11 11:35
 * @Version 1.0
 */

import java.io.FileReader;
//import java.io.FileWriter;
import java.io.IOException;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;

class Tools {
    public final int maxsize = 200;
    String savwd[] = {"main", "int", "float", "char", "double", "long", "return", "if", "case", "switch", "break", "default", "printf", "scanf", "define", "include"};//保留字数组;
    char operate[] = {'=', '>', '<', '?', '!', '+', '-', '*', '/', '%', '(', ')', ':'};//操作符数组
    char seprate[] = {',', ';', '{', '}', '"'};//分隔符数组
    String doperate[] = {"==", "+=", "-=", ">=", "<=", "!=", "=", "+", "-", "<", ">", "!", "*", "/", "%", "(", ")", "++", "--", "()"};
}

class Monitor {
    public int flag;
    public String string;
}

public class DFA2 {
    static Monitor analyste(char array[]) {//对读取的窜进行分析
        Tools get = new Tools();
        Monitor monitor = new Monitor();
        int flag = 0, numbercount = 0;
        int countnumber;
        for (countnumber = 0; array[countnumber] != '\0'; countnumber++) ;
        String str = new String(array);
        str = str.substring(0, countnumber);
        for (int count = 0; count < get.savwd.length; count++)
            if (str.equals(get.savwd[count])) {
                flag = 1;
                break;
            }
        if (flag == 1) {//是否为关键字
            monitor.flag = 1;
        } else if (array[0] >= '0' && array[0] <= '9') {//判断是否为常量
            numbercount = 1;
            for (int count = numbercount; count < str.length(); count++)
                if (array[count] >= '0' && array[count] <= '9')
                    numbercount++;
            if (numbercount < str.length()) {//判断是否为错误表示符
                monitor.flag = 2;
            } else if (numbercount == str.length()) {//判断是否是常量
                monitor.flag = 3;
            }
        } else if ((array[0] >= 'a' && array[0] <= 'z') || (array[0] >= 'A' && array[0] <= 'Z')) {//判断是否是表示符
            monitor.flag = 4;
        }
        monitor.string = str;
        return monitor;
    }

    static boolean iseprate(char o)//判断是否是分割符
    {
        Tools get = new Tools();
        int flag = 0;
        for (int count = 0; count < get.seprate.length; count++) {
            if (o == get.seprate[count]) {
                flag = 1;
                break;
            }
        }
        return (flag == 1);
    }

    static boolean isoperate(char c) {//判断是否是运算符
        Tools get = new Tools();
        int flag = 0;
        for (int count = 0; count < get.operate.length; count++) {
            if (c == (get.operate[count])) {
                flag = 1;
                break;
            }
        }
        return (flag == 1);
    }

    static Monitor analystoperate(char doubles[])//此函数用于分析操作数组，并返回分析状态值给MONITOR，共输出程序调用
    {
        int count;
        int flag = 0;
        Tools tl = new Tools();
        Monitor temp = new Monitor();
        String str = new String(doubles);
        for (count = 0; doubles[count] != '\0'; count++) ;
        str = str.substring(0, count);
        for (int i = 0; i < tl.doperate.length; i++) {//判断操作符的合法性，并且给MONITOR 设定状态
            if (str.equals(tl.doperate[i])) {
                flag = 1;
                break;
            }
        }
        temp.flag = flag;
        temp.string = str;
        return temp;
    }

    public static void main(String args[]) throws IOException {
        Tools get = new Tools();
        FileReader in = new FileReader("C:\\myjava\\testdata.txt");
        FileOutputStream file = new FileOutputStream("C:\\myjava\\result.txt", true);
        OutputStreamWriter out = new OutputStreamWriter(file);
        int temp;
        int flag = 0;
        char operate[] = new char[get.maxsize];
        int operatecount = 0;
        int operateflag = 0;
        Monitor result = new Monitor();
        Monitor oresult = new Monitor();
        char temparray[] = new char[get.maxsize];
        System.out.println("符号 名称 说明");
        out.write("符号 名称 说明" + "\n");
        System.out.println();
        while ((temp = in.read()) != -1) {//读文件
            if (temp != ' ' && !iseprate((char) temp) && !isoperate((char) temp) && temp != '\n')
                temparray[flag++] = (char) temp;
            else {
                result = analyste(temparray);
                char character[] = {(char) temp};
                String word = result.string;
                if (result.flag == 1) {
                    System.out.println(word + " 关键字");
                    out.write(word + " 关键字");
                    out.write("\n");
                }
                if (result.flag == 2) {
                    System.out.println(word + " 标示符 error");
                    out.write(word + " 标示符 error");
                    out.write("\n");
                }
                if (result.flag == 3) {
                    System.out.println(word + " 常量 ");
                    out.write(word + " 常量 ");
                    out.write("\n");
                }
                if (result.flag == 4) {
                    System.out.println(word + " 标示符");
                    out.write(word + " 标示符");
                    out.write("\n");
                }
                if (result.flag == 5) {
                    System.out.println(word + " 关键字");
                    out.write(word + " 关键字");
                    out.write("\n");
                }
                if (iseprate((char) temp)) {
                    String s = new String(character);
                    System.out.println(s + " 分隔符");
                    out.write(s + " 分隔符");
                    out.write("\n");
                }
                if (isoperate((char) temp)) {//判断是否是操作符并保存操作符到相应的数组
                    operate[operatecount++] = (char) temp;
                    operateflag++;
//continue;
                } else if (operateflag != 0) {
                    oresult = analystoperate(operate);//分析操作符数组
                    if (oresult.flag == 1) {//输出正确的操纵符
                        out.write(oresult.string + " 操作符" + "\n");
                        System.out.println(oresult.string + " 操作符");
                    } else {//输出错误操作符
                        out.write(oresult.string + " 操作符" + " ERROR" + "\n");
                        System.out.println(oresult.string + " 操作符" + " ERROR");
                    }
                    for (int count = 0; count < get.maxsize; count++) {//操作符数组归零
                        operate[count] = '\0';
                    }
                    operateflag = 0;
                    operatecount = 0;
                }
                flag = 0;
                for (int count = 0; count < result.string.length(); count++)//标示符数组归零
                    temparray[count] = '\0';
                continue;
            }
        }
        System.out.println("分析完毕");
        in.close();
        out.close();
    }
}
/*程序说明：
 * 此程序用于简单C语言程序的词法分析，如果想扩大其检索的范围包括语言的种类等等，可在Tools类内部进行扩充文件。
 * 此程序有一个弊端，操作符的输出有一定的滞后性，还有待改进
 */